/*
 * Copyright 2006-2007 S W McIlroy
 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 * you may not use  this file  except in  compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed  under the  License is distributed on an "AS IS" BASIS,
 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 * implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.mockfu;

import static org.mockfu.Mocks.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Calendar;
import java.util.concurrent.locks.ReadWriteLock;

import org.testng.annotations.Test;

public class ProxyTest
{
    @Test
    public void noConstructor()
    {
        ProxyBuilder<File> proxy = ProxyBuilder.of( File.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return new File("intercepted!");
            }
        } );

        File obj = proxy.create();
        assertThat(obj != null);
        assertThat(obj.getAbsoluteFile(), new File("intercepted!"));

    }

    @Test
    public void iface()
    {
        ProxyBuilder<ReadWriteLock> proxy = ProxyBuilder.of(ReadWriteLock.class, new MethodInterceptor()
        {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return null;
            }
        } );

        ReadWriteLock obj = proxy.create();
        assertThat(obj.readLock() == null);
        assertThat(obj.toString() == null);
    }

    @Test
    public void defaultReturnValue()
    {
        ProxyBuilder<Object> proxy = ProxyBuilder.of(Object.class, new MethodInterceptor()
        {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return null;
            }
        } );

        assertThat(proxy.create().hashCode(), 0);
        assertThat(proxy.create().equals( null ), false);
    }

    @Test
    public void constructor()
    {
        ProxyBuilder<File> proxy = ProxyBuilder.of( File.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return "/flarp";
            }
        } );

        File obj = proxy.create( "/waldo" );
        assertThat(obj != null);
        assertThat(obj.getAbsolutePath(), "/flarp");
    }

    @Test
    public void interceptInConstructor()
    {
        ProxyBuilder<Waldo> proxy = ProxyBuilder.of( Waldo.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return "flarp";
            }
        } );


        Waldo obj = proxy.create(new Object[0]);
        assertThat(obj != null);
        assertThat(obj.value, "flarp");
    }


    static class Waldo
    {
        final String value;

        Waldo()
        {
            value = getValue();
        }

        String getValue()
        {
            return "waldo";
        }
    }

    @Test
    public void primitiveArgs()
    {
        final int[] matches = new int[1];

        ProxyBuilder<Calendar> proxy = new ProxyBuilder<Calendar>( Calendar.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                String name = context.getMethod().getName();
                if (name.equals( "roll" ) && (Integer)context.getArguments()[0] == 10)
                    matches[0]++;
                if (name.equals( "roll" ) && (Boolean)context.getArguments()[1])
                    matches[0]++;
                if (name.equals( "setTimeInMillis" ) && (Long)context.getArguments()[0] == 5)
                    matches[0]++;
                return null;
            }
        } );

        Calendar calendar = proxy.create();
        calendar.roll( 10, true );
        calendar.setTimeInMillis( 5 );

        assertThat(matches[0], 3);
    }

    @Test(expectedExceptions=FileNotFoundException.class)
    public void exception()
    {
        ProxyBuilder<Object> proxy = new ProxyBuilder<Object>( Object.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                throw new FileNotFoundException();
            }
        } );

        proxy.create().toString();
    }

    @Test
    public void packageVisibleClass()
    {
        assertThat((Multiplicity.class.getModifiers() & 7), 0);

        ProxyBuilder<Multiplicity> proxy = new ProxyBuilder<Multiplicity>( Multiplicity.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return "flarp";
            }
        } );

        Multiplicity multiplicity = proxy.create();
        assertThat(multiplicity.toString(), "flarp");
    }


    @Test
    public void packageVisibleMethod()
    throws Exception
    {
//        assertThat((Replacement.class.getMethod( "getValue", new Class[0] ).getModifiers() & 7), 0);

        ProxyBuilder<Replacement> proxy = new ProxyBuilder<Replacement>( Replacement.class, new MethodInterceptor() {
            public Object intercept( InvocationContext context ) throws Throwable
            {
                return "flarp";
            }
        } );

        Replacement replacement = proxy.create();
        assertThat(replacement.getValue2(), "flarp");
    }
}
